/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
 *
 * Zhiqim Kernel is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.kernel.websocket;

import java.io.IOException;
import java.io.InputStream;

import org.zhiqim.kernel.constants.CodeConstants;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.Bytes;
import org.zhiqim.kernel.util.Streams;

/**
 * WebSocket工具类：
 * 1、从流中读出一个WebSocket数据包
 * 2、生成数据包
 *
 * @version v1.5.2 @author zouzhigang 2020-4-10 新建与整理
 */
public class WebSockets implements CodeConstants
{
    /**
     * 解析流转为WebSocket数据包
     * 
     * @param in            输入流
     * @return              数据包
     * @throws IOException  异常
     */
    public static WebSocketPacket parse(InputStream in) throws IOException
    {
        int first = in.read() & 0xFF;
        int second = in.read() & 0xFF;
        
        WebSocketPacket packet = new WebSocketPacket();
        
        //1.FIN
        packet.fin = (first & 0x80) != 0;
        
        //2.opcode
        packet.opcode = first & 0x0F;
        
        //3.mask
        packet.mask = (second & 0x80) != 0;
        
        //4.len
        packet.len = packet.dataLen = second & 0x7F;//当len<126时，数据长度为单字节长度，取值为length
        if (packet.isTwoLength())
        {//2字节表示长度
            byte[] buf = Streams.getBytes(in, 2);
            packet.dataLen = Bytes.BU.getShortUnsigned(buf, 0);
        }
        else if (packet.isEightLength())
        {//8字节表示长度
            byte[] buf = Streams.getBytes(in, 8);
            long len = Bytes.BU.getLong(buf, 0);
            if (len > Integer.MAX_VALUE)
                throw Asserts.exception("超出支持的能力");
            
            packet.dataLen = (int)len;
        }
        
        if (packet.isMask())
        {//5.有掩码，取4字节
            packet.maskingKey = Streams.getBytes(in, 4);
        }
        
        if (packet.dataLen > 0)
        {//6.有数据
            packet.data = Streams.getBytes(in, packet.dataLen);
            if (packet.isMask())
            {//存在掩码的情况，作处理
                for (int i=0;i<packet.dataLen;i++)
                {
                    packet.data[i] = (byte)(packet.data[i] ^ packet.maskingKey[i % 4]);
                }
            }
        }
        
        return packet;
    }
    
    /** 生成文本数据包 */
    public static byte[] buildText(String text)
    {
        return new WebSocketPacket().setText(text).toPacket();
    }
    
    /** 生成二进制流数据包 */
    public static byte[] buildBinary(byte[] binary)
    {
        return new WebSocketPacket().setBinary(binary).toPacket();
    }
    
    /** 生成PING数据包 */
    public static byte[] buildPing()
    {
        return new WebSocketPacket().toPacket();
    }
    
    /** 生成PONG数据包 */
    public static byte[] buildPong()
    {
        return new WebSocketPacket().toPacket();
    }
}
